/*
 * Created on 2008-3-7
 *
 * TODO
 */
package jacky.lanlan.song.extension.struts.interceptor;

import java.lang.reflect.Method;
import java.util.Map;

import jacky.lanlan.song.closure.ReturnableHandler;
import jacky.lanlan.song.extension.struts.InfrastructureKeys;
import jacky.lanlan.song.extension.struts.action.ValueStack;
import jacky.lanlan.song.reflection.ReflectionUtils;
import jacky.lanlan.song.util.cache.ConcurrentCache;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.Globals;

/**
 * 处理Cancell操作的拦截器，优先级200。
 * 
 * @author Jacky.Song
 */
public class CancellInterceptor extends ActionInterceptorAdapter {

	// Cancell方法缓存 [全类名+方法名 -> 方法]
	private final ConcurrentCache<String,Method,Object[]> cancelledMethodCache=
		new ConcurrentCache<String,Method,Object[]>(
				new ReturnableHandler<Object[], Method>() { // 参数 [0]为actionClass，[1]为Cancell方法名
    			public Method doWith(Object[] data) {
    				Class<?> actionClass=(Class<?>) data[0];
    				String methodName=(String) data[1];
    				Method cancelled = ReflectionUtils.findMethod(
    						actionClass, methodName, InfrastructureKeys.METHOD_PARAM);// 寻找Cancell方法
    				
    				if(cancelled==null) {
    					throw new UnsupportedOperationException(
    							"没有与方法 [" + methodName.split("_")[0]
							+ "] 匹配的Cancell方法 [" + methodName + "]");
    				}
    				return cancelled;
    			}
				}
		);
	
	@Override
	@SuppressWarnings({ "unused", "unchecked" })
	public String preHandle(HttpServletRequest request,
			HttpServletResponse response,Object action) throws Exception {
		// 针对Cancell操作
		if(request.getAttribute(Globals.CANCEL_KEY) != null) {
			// 寻找执行方法对应的cancell方法
			Method execMethod=(Method) request.getAttribute(InfrastructureKeys.EXECUTION);
			String cancellMethodName=execMethod.getName()+"_Cancelled";
			Class<?> actionClass=action.getClass();
			Method cancelled=cancelledMethodCache.cacheIfAbsent(
					actionClass.getName()+cancellMethodName, new Object[] {actionClass,cancellMethodName});
			
			ValueStack vs=(ValueStack)request.getAttribute(InfrastructureKeys.VSAC);
			Map<String,String> reqData = (Map)request.getAttribute(InfrastructureKeys.REQ_DATA);
			return (String) cancelled.invoke(action, new Object[] { vs, reqData });// 调用Cancell操作的方法
		}
		return null; // 继续调用下面的拦截器
	}

	public int priority() {
		return 200;
	}
}
